package com.tsd.jxc.sale.service.impl;

import com.tsd.base.dao.BaseInvoiceInfoMapper;
import com.tsd.base.entity.BaseInvoiceInfoExt;
import com.tsd.base.service.BaseCodeRuleService;
import com.tsd.common.vo.BatchDeleteLogicVo;
import com.tsd.core.annotation.GenSnQue;
import com.tsd.core.constants.Constants;
import com.tsd.core.constants.VersionConstants;
import com.tsd.core.datasource.DataSourceContextHolder;
import com.tsd.core.service.GetDuplicatedObj;
import com.tsd.core.thread.ThreadPoolTaskUtil;
import com.tsd.core.utils.DoubleUtil;
import com.tsd.core.utils.HlpUtils;
import com.tsd.core.utils.ListUtil;
import com.tsd.core.vo.ErrorCode;
import com.tsd.core.vo.HlpException;
import com.tsd.core.vo.HttpResult;
import com.tsd.core.vo.PageBean;
import com.tsd.jxc.JxcConstants;
import com.tsd.jxc.buy.dao.JxcBuyOrderDetailMapper;
import com.tsd.jxc.buy.dao.JxcBuyOrderMapper;
import com.tsd.jxc.buy.entity.JxcBuyOrderDetailExt;
import com.tsd.jxc.buy.entity.JxcBuyOrderExt;
import com.tsd.jxc.buy.service.JxcBuyOrderService;
import com.tsd.jxc.config.JxcCodeRuleConstants;
import com.tsd.jxc.fin.FinanceConstants;
import com.tsd.jxc.fin.dao.JxcFinanceAccountDetailMapper;
import com.tsd.jxc.fin.dao.JxcFinanceAccountMapper;
import com.tsd.jxc.fin.entity.JxcFinanceAccountDetailExt;
import com.tsd.jxc.fin.entity.JxcFinanceAccountExt;
import com.tsd.jxc.fin.job.JxcFinanceJob;
import com.tsd.jxc.order.entity.JxcOrderAmountDetailExt;
import com.tsd.jxc.order.service.JxcOrderAmountDetailService;
import com.tsd.jxc.sale.dao.JxcSaleOrderDetailMapper;
import com.tsd.jxc.sale.dao.JxcSaleOrderMapper;
import com.tsd.jxc.sale.entity.*;
import com.tsd.jxc.sale.service.JxcSaleOrderDetailService;
import com.tsd.jxc.sale.service.JxcSaleOrderService;
import com.tsd.jxc.sale.service.JxcSaleReturnBillService;
import com.tsd.jxc.setting.service.JxcSettingService;
import com.tsd.jxc.stock.StockConstants;
import com.tsd.jxc.stock.entity.JxcStockOutbillExt;
import com.tsd.jxc.stock.entity.JxcStockOutbillItemExt;
import com.tsd.jxc.stock.service.JxcStockGoodsService;
import com.tsd.jxc.stock.service.JxcStockOutbillService;
import com.tsd.jxc.vo.JxcSettingVo;
import com.tsd.service.BaseServiceImpl;
import com.tsd.system.dao.SysResourceMapper;
import com.tsd.system.entity.SysUser;
import com.tsd.system.entity.SysUserExt;
import com.tsd.thread.Callback;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

/**
 * 描述：JxcSaleOrder 服务实现层
 *
 * @author Hillpool
 * @date 2022/07/29 15:04:27
 */
@Service
public class JxcSaleOrderServiceImpl extends BaseServiceImpl implements JxcSaleOrderService, GetDuplicatedObj {

    @Resource
    private JxcSaleOrderMapper jxcSaleOrderMapper;
    @Resource
    private JxcSaleOrderDetailMapper jxcSaleOrderDetailMapper;
    @Resource
    private JxcFinanceAccountMapper jxcFinanceAccountMapper;
    @Resource
    private JxcFinanceAccountDetailMapper jxcFinanceAccountDetailMapper;
    @Resource
    private JxcBuyOrderDetailMapper jxcBuyOrderDetailMapper;
    @Resource
    private JxcOrderAmountDetailService jxcOrderAmountDetailService;
    @Resource
    private JxcBuyOrderMapper jxcBuyOrderMapper;
    @Resource
    private BaseInvoiceInfoMapper baseInvoiceInfoMapper;
    @Resource
    private SysResourceMapper sysResourceMapper;
    @Resource
    private JxcSaleOrderDetailService jxcSaleOrderDetailService;
    @Resource
    private BaseCodeRuleService baseCodeRuleService;
    @Resource
    private JxcStockOutbillService jxcStockOutbillService;
    @Resource
    private JxcSaleReturnBillService jxcSaleReturnBillService;
    @Resource
    private JxcBuyOrderService jxcBuyOrderService;
    @Resource
    private JxcSettingService jxcSettingService;
    @Resource
    private JxcFinanceJob jxcFinanceJob;
    @Resource
    private JxcStockGoodsService jxcStockGoodsService;

    @Override
    public JxcSaleOrder getJxcSaleOrderById(Long id) throws Exception {
        return jxcSaleOrderMapper.selectByPrimaryKey(id);
    }

    @Override
    public JxcSaleOrderExt queryBySid(String sid) throws Exception {
        JxcSaleOrderExt orderExt = jxcSaleOrderMapper.selectBySid(sid);
        if (orderExt != null) {
            List<JxcSaleOrderDetailExt> detailExtList = jxcSaleOrderDetailService.queryValidByOrderList(Collections.singletonList(orderExt.getSid()));
            orderExt.setDetail_list(detailExtList);
        }
        return orderExt;
    }

    private void checkReturn(List<String> list, Integer state) throws Exception {
        List<JxcSaleOrderExt> checkList = jxcSaleOrderMapper.selectValid4Return(list);
        List<JxcSaleOrderExt> filterList = ListUtil.filter(checkList, t -> !HlpUtils.isEmpty(t.getQty()) && t.getQty().doubleValue() > 0);
        if (!HlpUtils.isEmptyList(filterList)) {
            List<String> codeList = ListUtil.map(filterList, JxcSaleOrderExt::getCode);
            String msg = "销售订单：" + StringUtils.join(codeList, "、") + " 已生成退货单，";
            if (!HlpUtils.isEmpty(state)) {
                msg += "无法" + (state == 1 ? "审核" : "反审") + "！";
            } else {
                msg += "无法删除！";
            }
            throw new HlpException(msg);
        }
    }

    @Override
    public void deleteJxcSaleOrders(List<String> list, SysUser opUser) throws Exception {
        if (HlpUtils.isEmptyList(list)) {
            return;
        }
        JxcSaleOrderExt params = new JxcSaleOrderExt();
        params.setDr(0);
        params.setSid_list(list);
        List<JxcSaleOrderExt> orderExtList = jxcSaleOrderMapper.selectByEntity(params);
        if (HlpUtils.isEmptyList(orderExtList)) {
            throw new HlpException("订单信息为空");
        }
        // 检查销售单是否已对账
        List<JxcSaleOrderExt> filterPayReqList = ListUtil.filter(orderExtList, t -> !HlpUtils.isEmpty(t.getPay_req_state()) && Constants.VALUE_NO != t.getPay_req_state());
        if (!HlpUtils.isEmptyList(filterPayReqList)) {
            List<String> codeList = ListUtil.map(filterPayReqList, JxcSaleOrderExt::getCode);
            String msg = "销售单：" + StringUtils.join(codeList, "、") + " 已对账，无法删除";
            throw new HlpException(msg);
        }

        // 检查销售订单是否已生成退货单
        this.checkReturn(list, null);

        BatchDeleteLogicVo logicVo = new BatchDeleteLogicVo(opUser);
        logicVo.setSidList(list);
        jxcSaleOrderMapper.deleteLogicBySidList(logicVo);

        jxcSaleOrderDetailMapper.deleteLogicByOrderList(logicVo);

        jxcOrderAmountDetailService.deleteJxcOrderAmountDetailsByOrderSid(list, opUser);
    }

    @Override
    public boolean isDuplicated(Object obj, String code) {
        if (obj == null) {
            return false;
        }
        JxcSaleOrderExt orderExt = (JxcSaleOrderExt) obj;
        orderExt.setCode(code);
        return jxcSaleOrderMapper.selectDuplicatedCode(orderExt) != null;
    }

    @Override
    @GenSnQue(ruleCode = JxcCodeRuleConstants.TYPE_JXC_SALE_ORDER, clientFieldName = "client_sid", supplierFieldName = "")
    public void saveJxcSaleOrder(JxcSaleOrderExt record, SysUser opUser) throws Exception {
        if (HlpUtils.isEmpty(record.getId())) {
            record.setSys_group_sid(opUser.getGroup_sid());
            super.checkEmpty(record.getClient_sid(), "请提供参数：client_sid");
            if (!HlpUtils.isEmpty(record.getCode())) {
                //如果是手动设置了编号，则检查是否有相同的，有的话，置空后重新生成
                JxcSaleOrderExt same = jxcSaleOrderMapper.selectDuplicatedCode(record);
                if (same != null) {
                    record.setCode(null);
                }
            }
            String genCode = baseCodeRuleService.genCode(record.getClient_sid(), JxcCodeRuleConstants.TYPE_JXC_SALE_ORDER, JxcCodeRuleConstants.TYPE_NAME_JXC_SALE_ORDER, opUser, record.getCode(), record, this);
            record.setCode(genCode);
            if (HlpUtils.isEmpty(record.getFree_shipping())) {
                record.setFree_shipping(0);
            }
            record.setAudit_state(Constants.VALUE_NO);
            record.setState(Constants.VALUE_YES);
            super.autoInjectBaseData(record, opUser, this.TYPE_CREATE, new Date(), record.getOrder_date());
            jxcSaleOrderMapper.insertSelective(record);
            jxcSaleOrderDetailService.saveJxcSaleOrderDetail(record, opUser);
            // 生成收付款明细
            this.genOrderAmountDetail(record, opUser);
        } else {
            JxcSaleOrderExt same = jxcSaleOrderMapper.selectDuplicatedCode(record);
            if (same != null) {
                throw new HlpException("已存在相同编号的订单");
            }
            super.autoInjectBaseData(record, opUser, this.TYPE_UPDATE);
            super.updateYyyyMmdd(record, record.getOrder_date());
            jxcSaleOrderMapper.updateByPrimaryKeySelective(record);
            jxcSaleOrderDetailService.saveJxcSaleOrderDetail(record, opUser);
        }
        jxcSaleOrderDetailMapper.updateQty4BaseByOrderSid(record.getSid());
        // 更新采购单已售数量
        this.updateBuyOrderDetailSoldQty(Collections.singletonList(record.getSid()), record);
    }

    @Override
    public void checkBuyStock(JxcSaleOrderExt record) throws Exception {
        List<JxcSaleOrderDetailExt> detailExtList = record.getDetail_list();
        if (HlpUtils.isEmptyList(detailExtList)) {
            return;
        }
        String orderSid = record.getSid();
        if (HlpUtils.isEmpty(orderSid) && !HlpUtils.isEmpty(record.getId())) {
            JxcSaleOrder order = jxcSaleOrderMapper.selectByPrimaryKey(record.getId());
            if (order != null) {
                orderSid = order.getSid();
            }
        }
        List<JxcSaleOrderDetailExt> oldList = new ArrayList<>();
        if (!HlpUtils.isEmpty(orderSid)) {
            oldList = jxcSaleOrderDetailMapper.selectByOrderSid(orderSid);
        }
        List<String> buyOrderDetailList = ListUtil.filterMap(detailExtList, t -> !HlpUtils.isEmpty(t.getBuy_order_detail_sid()), JxcSaleOrderDetailExt::getBuy_order_detail_sid);
        if (HlpUtils.isEmptyList(buyOrderDetailList)) {
            return;
        }
        List<JxcBuyOrderDetailExt> buyOrderDetailExtList = jxcBuyOrderDetailMapper.selectBySids(buyOrderDetailList);
        if (HlpUtils.isEmptyList(buyOrderDetailExtList)) {
            return;
        }
        List<String> errList = new ArrayList<>();
        for (JxcBuyOrderDetailExt buyOrderDetailExt : buyOrderDetailExtList) {
//            double stockQty = HlpUtils.isEmpty(buyOrderDetailExt.getStock_qty()) ? 0D : buyOrderDetailExt.getStock_qty().doubleValue();
//            if (HlpUtils.isEmpty(buyOrderDetailExt.getOrder_audit_state()) || buyOrderDetailExt.getOrder_audit_state() == 0) {
//                stockQty = DoubleUtil.sub(buyOrderDetailExt.getQty(), buyOrderDetailExt.getSold_qty());
//            }
//            double lockQty = HlpUtils.isEmpty(buyOrderDetailExt.getLock_qty()) ? 0D : buyOrderDetailExt.getLock_qty().doubleValue();
//            lockQty = DoubleUtil.sub(lockQty, buyOrderDetailExt.getSold_qty());
//            if (lockQty > 0 && !HlpUtils.isEmptyList(oldList)) {
//                List<JxcSaleOrderDetailExt> filterOldList = ListUtil.filter(oldList, t -> buyOrderDetailExt.getSid().equals(t.getBuy_order_detail_sid()));
//                if (!HlpUtils.isEmptyList(filterOldList)) {
//                    for (JxcSaleOrderDetailExt ext : filterOldList) {
//                        lockQty = DoubleUtil.sub(lockQty, ext.getQty());
//                    }
//                }
//                if (lockQty > 0) {
//                    stockQty = DoubleUtil.sub(stockQty, lockQty);
//                }
//            }
            List<JxcSaleOrderDetailExt> checkList = ListUtil.filter(detailExtList, t -> buyOrderDetailExt.getSid().equals(t.getBuy_order_detail_sid()));
            if (HlpUtils.isEmptyList(checkList)) {
                continue;
            }
            double saleQty = 0D;
            for (JxcSaleOrderDetailExt ext : checkList) {
                saleQty = DoubleUtil.add(saleQty, ext.getQty());
            }
//            if (saleQty > stockQty) {
//                String err = buyOrderDetailExt.getGoods_name();
//                if (!HlpUtils.isEmpty(buyOrderDetailExt.getSpec_info())) {
//                    err += "-" + buyOrderDetailExt.getSpec_info();
//                }
//                errList.add(err);
//            }
        }
        if (!HlpUtils.isEmptyList(errList)) {
            String msg = "以下商品销售数量大于采购数量：\n" + StringUtils.join(errList, "、");
            throw new HlpException(msg);
        }
    }

    private void updateBuyOrderDetailSoldQty(List<String> orderList, JxcSaleOrderExt orderExt) {
        if (HlpUtils.isEmptyList(orderList) && orderExt == null) {
            return;
        }
        List<JxcSaleOrderDetailExt> detailExtList = ThreadPoolTaskUtil.queryInList4Split(orderList, list -> {
            JxcSaleOrderDetailExt params = new JxcSaleOrderDetailExt();
            params.setOrder_list(list);
            return jxcSaleOrderDetailMapper.selectByEntity(params);
        });
        if (orderExt != null && !HlpUtils.isEmptyList(orderExt.getDetail_list())) {
            detailExtList.addAll(orderExt.getDetail_list());
        }
        detailExtList = ListUtil.filter(detailExtList, t -> !HlpUtils.isEmpty(t.getBuy_order_detail_sid()));
        if (HlpUtils.isEmptyList(detailExtList)) {
            return;
        }
        List<String> detailList = ListUtil.map(detailExtList, JxcSaleOrderDetailExt::getBuy_order_detail_sid);
        jxcBuyOrderDetailMapper.updateLockAndSoldQty4Sale(detailList);
    }

    private void genOrderAmountDetail(JxcSaleOrderExt record, SysUser opUser) throws Exception {
        if (!HlpUtils.isEmpty(record.getReceived_amount()) && record.getReceived_amount().doubleValue() > 0) {
            JxcOrderAmountDetailExt detailExt = new JxcOrderAmountDetailExt();
            detailExt.setType(StockConstants.PAY_TYPE_FOR_SALE);
            detailExt.setThe_date(new Date());
            detailExt.setOrder_sid(record.getSid());
            detailExt.setAmount(record.getReceived_amount());
            detailExt.setRemain_amount(record.getUn_receive_amount());
            detailExt.setPay_type(record.getPay_type());
            jxcOrderAmountDetailService.saveJxcOrderAmountDetail(detailExt, opUser);
        }
    }

    @Override
    public List<JxcSaleOrderExt> findJxcSaleOrders(Map<String, Object> params, PageBean page) throws Exception {
        List<JxcSaleOrderExt> list = jxcSaleOrderMapper.selectByPage(params, page);
        String goods_name = HlpUtils.getString(params, "goods_name");
        if (!HlpUtils.isEmptyList(list) && !HlpUtils.isEmpty(goods_name)) {
            List<String> orderList = ListUtil.map(list, JxcSaleOrderExt::getSid);
            JxcSaleOrderDetailExt detailParams = new JxcSaleOrderDetailExt();
            detailParams.setDr(0);
            detailParams.setOrder_list(orderList);
            detailParams.setGoods_name(goods_name);
            List<JxcSaleOrderDetailExt> detailExtList = jxcSaleOrderDetailMapper.selectByEntity(detailParams);
            for (JxcSaleOrderExt orderExt : list) {
                List<JxcSaleOrderDetailExt> filterList = ListUtil.filter(detailExtList, t -> t.getOrder_sid().equals(orderExt.getSid()));
                orderExt.setDetail_list(filterList);
            }
        }
        return list;
    }

    @Override
    public List<JxcSaleOrderExt> findJxcSaleOrders(Map<String, Object> params) throws Exception {
        return jxcSaleOrderMapper.selectByParams(params);
    }

    @Override
    public void changeJxcSaleOrderAuditState(List<String> sidList, Integer state, JxcSettingVo settingVo, SysUserExt opUser) throws Exception {
        JxcSaleOrderExt params = new JxcSaleOrderExt();
        params.setDr(0);
        params.setSid_list(sidList);
        List<JxcSaleOrderExt> orderExtList = jxcSaleOrderMapper.selectByEntity(params);
        if (HlpUtils.isEmptyList(orderExtList)) {
            throw new HlpException("订单信息为空");
        }

        // 检查销售单是否已对账
        List<JxcSaleOrderExt> filterPayReqList = ListUtil.filter(orderExtList, t -> !HlpUtils.isEmpty(t.getPay_req_state()) && Constants.VALUE_NO != t.getPay_req_state());
        if (!HlpUtils.isEmptyList(filterPayReqList)) {
            List<String> codeList = ListUtil.map(filterPayReqList, JxcSaleOrderExt::getCode);
            String msg = "销售单：" + StringUtils.join(codeList, "、") + " 已对账";
            msg += "，无法" + (state == 1 ? "审核" : "反审");
            throw new HlpException(msg);
        }

        // 判断系统设置是否检查毛利率
        if (StockConstants.STATE_AUDITED == state && settingVo.isCheck_gross_profit_rate()) {
            // 不存在权限则检查毛利率
            List<JxcSaleOrderExt> filterList = ListUtil.filter(orderExtList, t -> {
                double check = DoubleUtil.sub(t.getGross_profit_rate(), settingVo.getDefault_gross_profit_rate());
                return check < 0;
            });
            if (!HlpUtils.isEmptyList(filterList)) {
                // 检查用户是否存在权限：特价审核
                Integer checkPermission = sysResourceMapper.checkRightByUser(opUser.getSid(), JxcConstants.SALE_ORDER_AUDIT_SPECIAL_PRICE);
                if (checkPermission == null) {
                    if (!HlpUtils.isEmpty(opUser.getDr()) && JxcSettingVo.STATE_ENABLE == settingVo.getAuto_approval_sale_order()) {
                        // 自动审核不抛出异常，直接返回
                        return;
                    }
                    List<String> codeList = ListUtil.map(filterList, JxcSaleOrderExt::getCode);
                    throw new HlpException("销售订单：" + StringUtils.join(codeList, "、") + " 毛利率低于系统设置的最低毛利率，没有审核权限");
                }
            }
        }

        // 检查销售订单是否已生成退货单
        this.checkReturn(sidList, state);

        boolean isFree = VersionConstants.accountSetVersionIsFree();
        for (JxcSaleOrderExt orderExt : orderExtList) {
            if (state == 1) {
                orderExt.setAudit_state(Constants.VALUE_YES);
                orderExt.setAuditor_sid(opUser.getSid());
                orderExt.setAuditor_name(opUser.getName());
                orderExt.setAudit_date(new Date());
                if (isFree) {
                    jxcStockGoodsService.updateBySaleOrder(Constants.OP_SUB, orderExt);
                }
            } else if (state == -1) {
                orderExt.setAudit_state(Constants.VALUE_NO);
                orderExt.setAuditor_sid(null);
                orderExt.setAuditor_name(null);
                orderExt.setAudit_date(null);
                if (isFree) {
                    jxcStockGoodsService.updateBySaleOrder(Constants.OP_ADD, orderExt);
                }
            }
            jxcSaleOrderMapper.updateByPrimaryKey(orderExt);
        }
    }

    @Override
    public HttpResult<Object> changeJxcSaleOrderAuditStateWithCheckStock(List<String> sidList, Integer state, String execute, String related_audit, SysUserExt opUser) throws Exception {
        JxcSaleOrderExt params = new JxcSaleOrderExt();
        params.setDr(0);
        params.setSid_list(sidList);
        List<JxcSaleOrderExt> orderExtList = jxcSaleOrderMapper.selectByEntity(params);
        if (HlpUtils.isEmptyList(orderExtList)) {
            return HttpResult.success(null);
        }

        // 审核
        if (Constants.VALUE_YES == state) {
            List<String> orderList = ListUtil.map(orderExtList, JxcSaleOrderExt::getSid);
            // 检查采购单是否已审核
            if (HlpUtils.isEmpty(related_audit)) {
                JxcBuyOrderExt checkBuyOrder = jxcBuyOrderMapper.select4CheckAuditState(orderList);
                if (checkBuyOrder != null) {
                    JxcSaleOrderExt orderExt = ListUtil.get(orderExtList, t -> t.getSid().equals(checkBuyOrder.getSid()));
                    if (orderExt != null) {
                        return HttpResult.fail(ErrorCode.CODE_CONFIRM_ERROR, "存在未审核的采购单，是否需要连带审核？");
                    }
                }
            }
            if (HlpUtils.isEmpty(execute)) {
                // 检查采购单库存
                List<JxcSaleOrderExt> checkList = jxcSaleOrderMapper.select4CheckStock(orderList);
                if (!HlpUtils.isEmptyList(checkList)) {
                    HttpResult<Object> data = HttpResult.success(checkList);
                    data.setCode(ErrorCode.CODE_CONFIRM_ERROR);
                    return data;
                }
            }
            if (!HlpUtils.isEmpty(related_audit)) {
                List<String> needAuditList = jxcBuyOrderMapper.selectNeedRelatedAudit(orderList);
                if (!HlpUtils.isEmptyList(needAuditList)) {
                    jxcBuyOrderService.changeJxcBuyOrderAuditState(needAuditList, 1, opUser);
                }
            }
        }
        boolean isFree = VersionConstants.accountSetVersionIsFree();
        for (JxcSaleOrderExt orderExt : orderExtList) {
            if (state == 1) {
                orderExt.setAudit_state(Constants.VALUE_YES);
                orderExt.setAuditor_sid(opUser.getSid());
                orderExt.setAuditor_name(opUser.getName());
                orderExt.setAudit_date(new Date());
                if (isFree) {
                    jxcStockGoodsService.updateBySaleOrder(Constants.OP_SUB, orderExt);
                }
            } else if (state == -1) {
                orderExt.setAudit_state(Constants.VALUE_NO);
                orderExt.setAuditor_sid(null);
                orderExt.setAuditor_name(null);
                orderExt.setAudit_date(null);
                if (isFree) {
                    jxcStockGoodsService.updateBySaleOrder(Constants.OP_ADD, orderExt);
                }
            }
            jxcSaleOrderMapper.updateByPrimaryKey(orderExt);
        }
        List<String> orderList = ListUtil.map(orderExtList, JxcSaleOrderExt::getSid);
        ThreadPoolTaskUtil.executeInList4Split(orderList, false, itemList -> {
            //2023-10-14 wudw, 原sql执行大于10秒，进行优化，快了很多：通过二次查询来减少关联，将buy_order_detail的sid先查询，然后再进行二次查询
//            in()适合子查询结果集比外表查询结果集小的情况（子表查询结果集的记录数决定了数据库的交互次数）
//            exists()适合子查询结果集比外表查询结果集大的情况（外表查询结果集的记录数决定了数据库的交互次数）
//            当外表查询结果集与子查询结果集数据一样大时，in与exists效率差不多,可任选一个使用
            List<String> buyOrderDetailSidList = jxcBuyOrderDetailMapper.selectSidByOrderSid(itemList);
            if (buyOrderDetailSidList != null && buyOrderDetailSidList.size() > 0) {
                jxcBuyOrderDetailMapper.updateSoldStockQty4SaleAudit(buyOrderDetailSidList);
            }
        });
        return HttpResult.success(null);
    }

    private List<JxcSaleOrderExt> queryBySidList(List<String> sidList) {
        List<JxcSaleOrderExt> orderExtList = ThreadPoolTaskUtil.queryInList4Split(sidList, list -> {
            JxcSaleOrderExt params = new JxcSaleOrderExt();
            params.setDr(0);
            params.setSid_list(list);
            return jxcSaleOrderMapper.selectByEntity(params);
        });
        if (HlpUtils.isEmptyList(orderExtList)) {
            return null;
        }
        List<String> orderList = ListUtil.map(orderExtList, JxcSaleOrderExt::getSid);
        List<JxcSaleOrderDetailExt> detailExtList = ThreadPoolTaskUtil.queryInList4Split(orderList, list -> jxcSaleOrderDetailService.queryValidByOrderList(list));
        if (HlpUtils.isEmptyList(detailExtList)) {
            return null;
        }
        for (JxcSaleOrderExt orderExt : orderExtList) {
            List<JxcSaleOrderDetailExt> filterList = ListUtil.filter(detailExtList, t -> t.getOrder_sid().equals(orderExt.getSid()));
            if (HlpUtils.isEmptyList(filterList)) {
                continue;
            }
            orderExt.setDetail_list(filterList);
        }
        return ListUtil.filter(orderExtList, t -> !HlpUtils.isEmptyList(t.getDetail_list()));
    }

    @Override
    public void genJxcSaleOrder2OutBill(List<String> sidList, SysUserExt opUser) throws Exception {
        List<JxcSaleOrderExt> orderExtList = this.queryBySidList(sidList);
        orderExtList = ListUtil.filter(orderExtList, t -> !StockConstants.IN_OUT_BILL_ALL.equals(t.getOut_bill()));
        if (HlpUtils.isEmptyList(orderExtList)) {
            return;
        }

        // 检查库存数量是否足够
        List<String> orderList = ListUtil.map(orderExtList, JxcSaleOrderExt::getSid);
        JxcSaleOrderDetailExt checkDetailExt = jxcSaleOrderDetailMapper.checkStockQty4GenOutBill(orderList);
        if (checkDetailExt != null) {
            String error = "商品：" + checkDetailExt.getGoods_name();
            if (!HlpUtils.isEmpty(checkDetailExt.getSpec_info())) {
                error += "（" + checkDetailExt.getSpec_info() + "）";
            }
            error += "库存不足，暂时无法生成出库单。";
            throw new HlpException(error);
        }

        List<JxcSaleOrderExt> updateList = new ArrayList<>();
        List<JxcSaleOrderDetailExt> updateDetailList = new ArrayList<>();
        for (JxcSaleOrderExt orderExt : orderExtList) {
            JxcStockOutbillExt outBillExt = orderExt.genOutBill(null);
            if (HlpUtils.isEmptyList(outBillExt.getItem_list())) {
                continue;
            }
            jxcStockOutbillService.saveJxcStockOutbill(outBillExt, opUser);

            orderExt.setOut_bill(StockConstants.IN_OUT_BILL_ALL);
            orderExt.setOut_bill_sid(outBillExt.getSid());
            super.autoInjectBaseData(orderExt, opUser, this.TYPE_UPDATE);
            updateList.add(orderExt);

            for (JxcSaleOrderDetailExt detailExt : orderExt.getDetail_list()) {
                detailExt.setOut_bill(StockConstants.DETAIL_IN_OUT_BILL_ALL);
                JxcStockOutbillItemExt itemExt = ListUtil.get(outBillExt.getItem_list(), t -> t.getSrc_sid().equals(detailExt.getSid()));
                if (itemExt != null) {
//                    detailExt.setOut_bill_item_sid(itemExt.getSid());
                }
                super.autoInjectBaseData(detailExt, opUser, this.TYPE_UPDATE);
                updateDetailList.add(detailExt);
            }
        }
        if (!HlpUtils.isEmptyList(updateList)) {
            ThreadPoolTaskUtil.executeInList4Split(updateList, false, itemList -> jxcSaleOrderMapper.updateList(itemList));
        }
        if (!HlpUtils.isEmptyList(updateDetailList)) {
            ThreadPoolTaskUtil.executeInList4Split(updateDetailList, false, itemList -> jxcSaleOrderDetailMapper.updateList(itemList));
        }
    }

    @Override
    public void genJxcSaleOrder2ReturnBill(List<String> sidList, SysUserExt opUser) throws Exception {
        List<JxcSaleOrderExt> orderExtList = this.queryBySidList(sidList);
        if (HlpUtils.isEmptyList(orderExtList)) {
            return;
        }
        List<String> unionClientList = ListUtil.map(orderExtList, JxcSaleOrderExt::getClient_sid);
        for (String clientSid : unionClientList) {
            List<JxcSaleOrderExt> filterList = ListUtil.filter(orderExtList, t -> clientSid.equals(t.getClient_sid()));
            if (HlpUtils.isEmptyList(filterList)) {
                continue;
            }
            List<JxcSaleOrderDetailExt> detailExtList = new ArrayList<>();
            for (JxcSaleOrderExt orderExt : filterList) {
                detailExtList.addAll(orderExt.getDetail_list());
            }
            JxcSaleOrderExt orderExt = filterList.get(0).copy();
            orderExt.setDetail_list(detailExtList);
            JxcSaleReturnBillExt billExt = orderExt.genReturnBill();
            if (HlpUtils.isEmptyList(billExt.getDetail_list())) {
                continue;
            }
            jxcSaleReturnBillService.saveJxcSaleReturnBill(billExt, opUser);
        }
    }

    @Override
    public JxcSaleReturnBillExt getJxcSaleOrder2ReturnBillData(String sid) throws Exception {
        JxcSaleOrderExt orderExt = this.queryBySid(sid);
        super.checkEmpty(orderExt, "销售订单不存在");
        return orderExt.genReturnBill();
    }

    @Override
    public Integer genJxcFinanceAccountDetail4Sale(List<String> sidList, SysUserExt opUser) throws Exception {
        //根据销售订单sid列表生成对账单
        JxcSaleOrderExt params = new JxcSaleOrderExt();
        params.setDr(0);
        params.setSid_list(sidList);
        List<JxcSaleOrderExt> orderExtList = jxcSaleOrderMapper.selectByEntity(params);
        if (HlpUtils.isEmptyList(orderExtList)) {
            return 0;
        }
        List<JxcSaleOrderExt> filterList = ListUtil.filter(orderExtList, t -> !HlpUtils.isEmpty(t.getGen_finance()) && t.getGen_finance() == 1);
        if (!HlpUtils.isEmptyList(filterList)) {
            List<String> codeList = ListUtil.map(orderExtList, JxcSaleOrderExt::getCode);
            throw new HlpException("销售订单：" + StringUtils.join(codeList, "、") + " 已生成对账！");
        }

        List<String> clientList = ListUtil.map(orderExtList, JxcSaleOrderExt::getClient_sid);
        // 查询账户余额
        List<JxcFinanceAccountExt> accountExtList = jxcFinanceAccountMapper.selectValidByPartyList(clientList);
        Map<String, Double> remainAmountMap = new HashMap<>();
        List<JxcSaleOrderExt> updateList = new ArrayList<>();
        List<JxcFinanceAccountDetailExt> list = new ArrayList<>();
        String dataSource = DataSourceContextHolder.getDataSourceType();
        for (JxcSaleOrderExt orderExt : orderExtList) {
            JxcFinanceAccountExt accountExt = ListUtil.get(accountExtList, t -> t.getRelated_party_sid().equals(orderExt.getClient_sid()));
            List<JxcFinanceAccountDetailExt> detailExtList = orderExt.genAccountDetail();
            if (!HlpUtils.isEmptyList(detailExtList)) {
                for (JxcFinanceAccountDetailExt detailExt : detailExtList) {
                    super.autoInjectBaseData(detailExt, opUser, this.TYPE_CREATE);
                    double remainAmount = 0D;
                    if (remainAmountMap.containsKey(orderExt.getClient_sid())) {
                        remainAmount = remainAmountMap.get(orderExt.getClient_sid());
                    } else if (accountExt != null) {
                        remainAmount = accountExt.getAmount().doubleValue();
                    }
                    if (FinanceConstants.OP_ADD.equals(FinanceConstants.getAccountTypeOp(dataSource, detailExt.getBill_type()))) {
                        remainAmount = DoubleUtil.add(remainAmount, FinanceConstants.getAmount(detailExt));
                    } else {
                        remainAmount = DoubleUtil.sub(remainAmount, FinanceConstants.getAmount(detailExt));
                    }
                    remainAmountMap.put(orderExt.getClient_sid(), remainAmount);
                    detailExt.setRemain_amount(BigDecimal.valueOf(remainAmount));
                    //TODO 编码的生成是否有问题？
                    String genCode = baseCodeRuleService.genCode(detailExt.getRelated_party_sid(), JxcCodeRuleConstants.TYPE_JXC_FINANCE_ACCOUNT, JxcCodeRuleConstants.TYPE_NAME_JXC_FINANCE_ACCOUNT, opUser, null, null, null);
                    detailExt.setCode(genCode);
                    list.add(detailExt);
                }
            }

            JxcSaleOrderExt updateData = new JxcSaleOrderExt();
            updateData.setId(orderExt.getId());
            updateData.setSid(orderExt.getSid());
            updateData.setGen_finance(1);
            super.autoInjectBaseData(updateData, opUser, this.TYPE_UPDATE);
            updateList.add(updateData);
        }

        ThreadPoolTaskUtil.executeInList4Split(list, false, itemList -> jxcFinanceAccountDetailMapper.insertList(itemList));

        // 更新字段：gen_finance
        ThreadPoolTaskUtil.executeInList4Split(updateList, false, itemList -> jxcSaleOrderMapper.updateList(itemList));

        // 添加更新账户余额到任务队列
        for (JxcFinanceAccountDetailExt detailExt : list) {
            jxcFinanceJob.addJxcFinanceQue(FinanceConstants.QUEUE_OP_INSERT, FinanceConstants.BIZ_NAME_FINANCE, "updateFinanceAmount", detailExt.getId(), opUser);
        }
        return list.size();
    }

    @Override
    public List<JxcSaleOrderExt> findJxcSaleOrdersIncludeDetail(Map<String, Object> params, PageBean page) {
        return jxcSaleOrderMapper.selectSaleOrdersIncludeDetailByPage(params, page);
    }

    @Override
    public List<JxcSaleOrderExt> queryJxcSaleOrderData4Print(List<String> sidList) throws Exception {
        List<JxcSaleOrderExt> list = ThreadPoolTaskUtil.queryInList4Split(sidList, itemList -> {
            JxcSaleOrderExt params = new JxcSaleOrderExt();
            params.setDr(0);
            params.setSid_list(itemList);
            return jxcSaleOrderMapper.selectByEntity(params);
        });
        if (!HlpUtils.isEmptyList(list)) {
            List<String> orderList = ListUtil.map(list, JxcSaleOrderExt::getSid);
            List<JxcSaleOrderDetailExt> detailExtList = jxcSaleOrderDetailService.queryValidByOrderList(orderList);
            for (JxcSaleOrderExt orderExt : list) {
                List<JxcSaleOrderDetailExt> filterList = ListUtil.filter(detailExtList, t -> t.getOrder_sid().equals(orderExt.getSid()));
                orderExt.setDetail_list(filterList);
            }
        }
        return list;
    }

    @Override
    public List<JxcSaleOrderExt> queryXdSaleOrderData4Print(List<String> sidList) throws Exception {
        List<JxcSaleOrderExt> orderExtList = this.queryJxcSaleOrderData4Print(sidList);
        if (!HlpUtils.isEmptyList(orderExtList)) {
            for (JxcSaleOrderExt orderExt : orderExtList) {
                orderExt.setClient_linker_name(orderExt.getRecver_name());
                orderExt.setClient_linker_mobile(orderExt.getRecver_phone());
                orderExt.setClient_linker_address(orderExt.getRecver_address());
            }
        }
        return orderExtList;
    }

    private List<JxcSaleOrderExt> cancelJxcSaleOrderBase(List<String> sidList, SysUserExt opUser, Callback<List<JxcSaleOrderExt>> callback) throws Exception {
        JxcSaleOrderExt params = new JxcSaleOrderExt();
        params.setDr(0);
        params.setSid_list(sidList);
        List<JxcSaleOrderExt> orderExtList = jxcSaleOrderMapper.selectByEntity(params);
        if (HlpUtils.isEmptyList(orderExtList)) {
            return null;
        }

        if (callback != null) {
            callback.pre_action(orderExtList, opUser);
        } else {
            List<JxcSaleOrderExt> filterList = ListUtil.filter(orderExtList, t -> Constants.VALUE_NO == t.getState());
            if (!HlpUtils.isEmptyList(filterList)) {
                List<String> codeList = ListUtil.map(filterList, JxcSaleOrderExt::getCode);
                throw new HlpException("销售单：" + StringUtils.join(codeList, "、") + " 已作废");
            }
        }

        List<JxcSaleOrderExt> updateList = new ArrayList<>();
        for (JxcSaleOrderExt orderExt : orderExtList) {
            orderExt.setState(Constants.VALUE_NO);
            super.autoInjectBaseData(orderExt, opUser, this.TYPE_UPDATE);
            updateList.add(orderExt);
        }
        if (!HlpUtils.isEmptyList(updateList)) {
            ThreadPoolTaskUtil.executeInList4Split(updateList, false, itemList -> jxcSaleOrderMapper.updateList(itemList));
        }
        if (callback != null) {
            callback.post_action(orderExtList, opUser);
        }
        return orderExtList;
    }

    @Override
    public void cancelJxcSaleOrder(List<String> sidList, SysUserExt opUser) throws Exception {
        List<JxcSaleOrderExt> orderExtList = this.cancelJxcSaleOrderBase(sidList, opUser, null);

        // 更新采购单已售数量
        List<String> orderList = ListUtil.map(orderExtList, JxcSaleOrderExt::getSid);
        this.updateBuyOrderDetailSoldQty(orderList, null);
        jxcOrderAmountDetailService.cancelJxcOrderAmountDetailsByOrderSid(orderList, opUser);
    }

    @Override
    public List<JxcSaleOrderExt> queryXdSaleOrderData4CalTax() throws Exception {
        return jxcSaleOrderMapper.select4CalTax();
    }

}
